package cn.stylefeng.roses.kernel.ca.server.core.session;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.ca.api.CaSessionManagerApi;
import cn.stylefeng.roses.kernel.ca.api.cookie.CaSessionCookieCreator;
import cn.stylefeng.roses.kernel.ca.api.expander.CaServerConfigExpander;
import cn.stylefeng.roses.kernel.ca.api.pojo.sso.CaLoginUser;
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
import cn.stylefeng.roses.kernel.rule.util.HttpServletUtil;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.HashSet;
import java.util.Set;

/**
 * Session实现
 *
 * @author fengshuonan
 * @date 2021/1/21 16:59
 */
public class DefaultCaSessionManager implements CaSessionManagerApi {

    /**
     * 登录用户缓存
     */
    private final CacheOperatorApi<CaLoginUser> loginUserCacheOperatorApi;

    /**
     * 用户token的缓存，这个缓存用来存储一个用户的所有token
     */
    private final CacheOperatorApi<Set<String>> allPlaceLoginTokenCache;

    /**
     * CA cookie的创建器，用在session创建时，给response添加cookie
     */
    private final CaSessionCookieCreator caSessionCookieCreator;

    public DefaultCaSessionManager(CacheOperatorApi<CaLoginUser> loginUserCacheOperatorApi,
                                   CacheOperatorApi<Set<String>> allPlaceLoginTokenCache,
                                   CaSessionCookieCreator caSessionCookieCreator) {
        this.loginUserCacheOperatorApi = loginUserCacheOperatorApi;
        this.allPlaceLoginTokenCache = allPlaceLoginTokenCache;
        this.caSessionCookieCreator = caSessionCookieCreator;
    }

    @Override
    public CaLoginUser getCaSession(String token) {
        return loginUserCacheOperatorApi.get(token);
    }

    @Override
    public void createCaSession(String token, CaLoginUser caLoginUser) {

        // 装配用户信息的缓存
        loginUserCacheOperatorApi.put(token, caLoginUser, CaServerConfigExpander.getCaSessionExpireSeconds());

        // 装配用户token的缓存
        Set<String> theUserTokens = allPlaceLoginTokenCache.get(caLoginUser.getUserId().toString());
        if (theUserTokens == null) {
            theUserTokens = new HashSet<>();
        }
        theUserTokens.add(token);
        allPlaceLoginTokenCache.put(caLoginUser.getUserId().toString(), theUserTokens);
    }

    @Override
    public void createCaSessionAndCookie(String token, CaLoginUser caLoginUser) {

        // 创建会话
        this.createCaSession(token, caLoginUser);

        // 添加用户的cookie信息
        String sessionCookieName = CaServerConfigExpander.getCookieName();
        Cookie cookie = caSessionCookieCreator.createCookie(sessionCookieName, token, Convert.toInt(CaServerConfigExpander.getCookieExpireSeconds()));
        HttpServletResponse response = HttpServletUtil.getResponse();
        response.addCookie(cookie);
    }

    @Override
    public void refreshSession(String token) {

        // 刷新缓存中的用户的过期时间
        CaLoginUser caLoginUser = loginUserCacheOperatorApi.get(token);
        if (caLoginUser != null) {
            loginUserCacheOperatorApi.expire(token, CaServerConfigExpander.getCaSessionExpireSeconds());
        }
    }

    @Override
    public void destroySession(String token) {

        // 销毁用户信息的缓存
        loginUserCacheOperatorApi.remove(token);

        // 销毁用户的cookie信息
        String sessionCookieName = CaServerConfigExpander.getCookieName();
        Cookie cookie = caSessionCookieCreator.createCookie(sessionCookieName, StrUtil.EMPTY, 0);
        HttpServletResponse response = HttpServletUtil.getResponse();
        response.addCookie(cookie);
    }

    @Override
    public void updateSession(String token, CaLoginUser caLoginUser) {
        if (caLoginUser != null) {
            loginUserCacheOperatorApi.put(token, caLoginUser);
        }
    }

    @Override
    public void offlineCaByAccountId(Long accountId) {
        if (null != accountId) {
            // 获取当前帐号的LOGGED_USERID中code信息
            Set<String> codes = this.allPlaceLoginTokenCache.get(accountId.toString());

            // 根据获取的code信息，删除对应的LOGGED_TOKEN信息
            if (CollectionUtil.isNotEmpty(codes)) {
                String[] codeString = codes.toArray(new String[codes.size()]);
                this.loginUserCacheOperatorApi.remove(codeString);
            }

            // 删除对应的LOGGED_USERID中code信息
            this.allPlaceLoginTokenCache.remove(accountId.toString());
        }
    }

}
